home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9310.ZIP / DFPP03.ZIP / EDITOR.CPP < prev    next >
C/C++ Source or Header  |  1993-09-27  |  11KB  |  510 lines

  1. // ----- editor.cpp
  2.  
  3. #include "editor.h"
  4. #include "desktop.h"
  5.  
  6. // ----------- common constructor code
  7. void Editor::OpenWindow()
  8. {
  9.     windowtype = EditorWindow;
  10.     row = 0;
  11.     tabs = 4;
  12.     insertmode = desktop.keyboard().InsertMode();
  13.     wordwrapmode = True;
  14.     DblBorder = False;
  15. }
  16.  
  17. // ---- keep the cursor out of tabbed space
  18. void Editor::AdjustCursorTabs(int key)
  19. {
  20.     while (CurrentChar() == Ptab)
  21.         key == FWD ? column++ : --column;
  22.     ResetCursor();
  23. }
  24.  
  25. // -------- process keystrokes
  26. void Editor::Keyboard(int key)
  27. {
  28.     int svwtop = wtop;
  29.     int svwleft = wleft;
  30.     switch (key)    {
  31.         case '\t':
  32.             InsertTab();
  33.             BuildTextPointers();
  34.             PaintCurrentLine();
  35.             ResetCursor();
  36.             break;
  37.         case ALT_P:
  38.             FormParagraph();
  39.             break;
  40.         case UP:
  41.             Upward();
  42.             break;
  43.         case DN:
  44.             Downward();
  45.             break;
  46.         case CTRL_HOME:
  47.             BeginDocument();
  48.             break;
  49.         case CTRL_END:
  50.             EndDocument();
  51.             break;
  52.         case '\r':
  53.             InsertCharacter('\n');
  54.             BuildTextPointers();
  55.             ResetCursor();
  56.             Paint();
  57.             break;
  58.         case DEL:
  59.         case RUBOUT:
  60.             visible = False;
  61.             EditBox::Keyboard(key);
  62.             visible = True;
  63.             BuildTextPointers();
  64.             PaintCurrentLine();
  65.             ResetCursor();
  66.             break;
  67.         default:
  68.             EditBox::Keyboard(key);
  69.             break;
  70.     }
  71.     if (svwtop != wtop || svwleft != wleft)
  72.         Paint();
  73. }
  74.  
  75. void Editor::Forward()
  76. {
  77.     if (CurrentChar())    {
  78.         if (CurrentChar() == '\n')    {
  79.             Home();
  80.             Downward();
  81.         }
  82.         else
  83.             EditBox::Forward();
  84.         AdjustCursorTabs(FWD);
  85.     }
  86. }
  87.  
  88. void Editor::Backward()
  89. {
  90.     if (column)
  91.         EditBox::Backward();
  92.     else if (row)    {
  93.         Upward();
  94.         End();
  95.     }
  96.     AdjustCursorTabs();
  97. }
  98.  
  99. void Editor::Upward()
  100. {
  101.     if (row)    {
  102.         if (row == wtop)
  103.             ScrollDown();
  104.         --row;
  105.         AdjustCursorTabs();
  106.     }
  107. }
  108.  
  109. void Editor::Downward()
  110. {
  111.     if (row < wlines)    {
  112.         if (row == wtop + ClientHeight() - 1)
  113.             ScrollUp();
  114.         row++;
  115.         AdjustCursorTabs();
  116.     }
  117. }
  118.  
  119. void Editor::BeginDocument()
  120. {
  121.     TextBox::Home();
  122.     column = 0;
  123.     row = 0;
  124.     AdjustCursorTabs();
  125. }
  126.  
  127. void Editor::EndDocument()
  128. {
  129.     TextBox::End();
  130.     row = wlines-1;
  131.     End();
  132.     AdjustCursorTabs();
  133. }
  134.  
  135. void Editor::ResetCursor()
  136. {
  137.     column = min(column, LineLength(row));
  138.     row = min(row, wlines);
  139.     SetCursorSize();
  140.     if (visible)
  141.         SetCursor(column, row);
  142. }
  143.  
  144. // ------- page up one screenfull
  145. void Editor::PageUp()
  146. {
  147.     row -= ClientHeight();
  148.     if (row < 0)
  149.         row = 0;
  150.     EditBox::PageUp();
  151.     AdjustCursorTabs();
  152. }
  153.  
  154. // ------- page down one screenfull
  155. void Editor::PageDown()
  156. {
  157.     row += ClientHeight();
  158.     if (row >= wlines)
  159.         row = wlines-1;
  160.     EditBox::PageDown();
  161.     AdjustCursorTabs();
  162. }
  163.  
  164. void Editor::InsertTab()
  165. {
  166.     visible = False;
  167.     if (insertmode)    {
  168.         EditBox::InsertCharacter('\t');
  169.         while ((column % tabs) != 0)
  170.             EditBox::InsertCharacter(Ptab);
  171.     }
  172.     else
  173.         do
  174.             Forward();
  175.         while ((column % tabs) != 0);
  176.     visible = True;
  177. }
  178.  
  179. // --- When inserting char, adjust next following tab, same line
  180. void Editor::AdjustTabInsert()
  181. {
  182.     visible = False;
  183.     // ---- test if there is a tab beyond this character
  184.     int savecol = column;
  185.     while (CurrentChar() && CurrentChar() != '\n')    {
  186.         if (CurrentChar() == '\t')    {
  187.             column++;
  188.             if (CurrentChar() == Ptab)
  189.                 EditBox::DeleteCharacter();
  190.             else
  191.                 for (int i = 0; i < tabs-1; i++)
  192.                     EditBox::InsertCharacter(Ptab);
  193.             break;
  194.         }
  195.         column++;
  196.     }
  197.     column = savecol;
  198.     visible = True;
  199. }
  200.  
  201. // --- test for wrappable word and wrap it
  202. void Editor::WordWrap()
  203. {
  204.     // --- test for word wrap
  205.     int len = LineLength(row);
  206.     int wd = ClientWidth()-1;
  207.     if (len >= wd)    {
  208.         const char *cp = TextLine(row);
  209.         char ch = *(cp + wd);
  210.         // --- test words beyond right margin
  211.         if (len > wd || (ch && ch != ' ' && ch != '\n'))    {
  212.             // --- test typing in last word in window's line
  213.             const char *cw = cp + wd;
  214.             cp += column;
  215.             while (cw > cp)    {
  216.                 if (*cw == ' ')
  217.                     break;
  218.                 --cw;
  219.             }
  220.             int newcol = 0;
  221.             if (cw <= cp)    {
  222.                 // --- user was typing last word on line
  223.                 // --- find beginning of the word
  224.                 const char *cp1 = TextLine(row);
  225.                 const char *cw1 = cw;
  226.                 while (*cw1 != ' ' && cw1 > cp1)
  227.                     --cw1, newcol++;
  228.                 wleft = 0;
  229.             }
  230.             FormParagraph();
  231.             if (cw <= cp)    {
  232.                 // --- user was typing last word on line
  233.                 column = newcol;
  234.                 if (cw == cp)
  235.                     --column;
  236.                 row++;
  237.                 ResetCursor();
  238.             }
  239.         }
  240.     }
  241. }
  242.  
  243. void Editor::InsertCharacter(int key)
  244. {
  245.     if (insertmode)    {
  246.         if (key != '\n')
  247.             AdjustTabInsert();
  248.     }
  249.     else if (CurrentChar() == '\t')    {
  250.         // --- overtyping a tab
  251.         visible = False;
  252.         column++;
  253.         while (CurrentChar() == Ptab)
  254.             EditBox::DeleteCharacter();
  255.         --column;
  256.     }
  257.     visible = False;
  258.     EditBox::InsertCharacter(key);
  259.     visible = True;
  260.     ResetCursor();
  261.     if (wordwrapmode)
  262.         WordWrap();
  263. }
  264.  
  265. // --- When deleting char, adjust next following tab, same line
  266. void Editor::AdjustTabDelete()
  267. {
  268.     visible = False;
  269.     // ---- test if there is a tab beyond this character
  270.     int savecol = column;
  271.     while (CurrentChar() && CurrentChar() != '\n')    {
  272.         if (CurrentChar() == '\t')    {
  273.             column++;
  274.             // --- count pseudo tabs
  275.             int pct = 0;
  276.             while (CurrentChar() == Ptab)
  277.                 pct++, column++;
  278.             if (pct == tabs-1)    {
  279.                 column -= tabs-1;
  280.                 for (int i = 0; i < tabs-1; i++)
  281.                     EditBox::DeleteCharacter();
  282.             }
  283.             else
  284.                 EditBox::InsertCharacter(Ptab);
  285.             break;
  286.         }
  287.         column++;
  288.     }
  289.     column = savecol;
  290.     visible = True;
  291. }
  292.  
  293. void Editor::DeleteCharacter()
  294. {
  295.     if (CurrentChar() == '\0')
  296.         return;
  297.     if (insertmode)
  298.         AdjustTabDelete();
  299.     if (CurrentChar() == '\t')    {
  300.         // --- deleting a tab
  301.         EditBox::DeleteCharacter();
  302.         while (CurrentChar() == Ptab)
  303.             EditBox::DeleteCharacter();
  304.         return;
  305.     }
  306.     const char *cp = TextLine(row);
  307.     const char *cw = cp + column;
  308.     const Bool delnewline = (Bool) (*cw == '\n');
  309.     const Bool reform = (Bool) (delnewline && *(cw+1) != '\n');
  310.     const Bool lastnewline = (Bool) (delnewline && *(cw+1) == '\0');
  311.     int newcol = 0;
  312.     if (reform && !lastnewline)    {
  313.         // --- user is deleting /n, find beginning of the last word
  314.         while (*--cw != ' ' && cw > cp)
  315.             newcol++;
  316.     }
  317.     EditBox::DeleteCharacter();
  318.     if (lastnewline)
  319.         return;
  320.     if (delnewline && !reform)    {
  321.         // --- user deleted a blank line
  322.         visible = True;
  323.         BuildTextPointers();
  324.         Paint();
  325.         return;
  326.     }
  327.     if (wordwrapmode && reform)    {
  328.         // --- user deleted /n
  329.         wleft = 0;
  330.         FormParagraph();
  331.         if (CurrentChar() == '\n')    {
  332.             // ---- joined the last word with next line's
  333.             //      first word and then wrapped the result
  334.             column = newcol;
  335.             row++;
  336.         }
  337.     }
  338. }
  339.  
  340. // --- form a paragraph from the current cursor position
  341. //    through one line before the next blank line or end of text
  342. void Editor::FormParagraph()
  343. {
  344.     int BegCol, FirstLine;
  345.     const char *BlkBegLine, *BlkEndLine, *BlkBeg;
  346.  
  347.     // ---- forming paragraph from cursor position
  348.     FirstLine = wtop + row;
  349.     BlkBegLine = BlkEndLine = TextLine(row);
  350.     if ((BegCol = column) >= ClientWidth())
  351.         BegCol = 0;
  352.     // ---- locate the end of the paragraph
  353.     while (*BlkEndLine)    {
  354.         Bool blank = True;
  355.         const char *BlankLine = BlkEndLine;
  356.         // --- blank line marks end of paragraph
  357.         while (*BlkEndLine && *BlkEndLine != '\n')    {
  358.             if (*BlkEndLine != ' ')
  359.                 blank = False;
  360.             BlkEndLine++;
  361.         }
  362.         if (blank)    {
  363.             BlkEndLine = BlankLine;
  364.             break;
  365.         }
  366.         if (*BlkEndLine)
  367.             BlkEndLine++;
  368.     }
  369.     if (BlkEndLine == BlkBegLine)    {
  370.         visible = True;
  371.         Downward();
  372.         return;
  373.     }
  374.     if (*BlkEndLine == '\0')
  375.         --BlkEndLine;
  376.     if (*BlkEndLine == '\n')
  377.         --BlkEndLine;
  378.     // --- change all newlines in block to spaces
  379.     BlkBeg = BlkBegLine;
  380.     while (BlkBeg < BlkEndLine)    {
  381.         if (*BlkBeg == '\n')    {
  382.             int off = BlkBeg - (const char *)*text;
  383.             (*text)[off] = ' ';
  384.         }
  385.         BlkBeg++;
  386.     }
  387.     // ---- insert newlines at new margin boundaries
  388.     BlkBeg = BlkBegLine;
  389.     while (BlkBegLine < BlkEndLine)    {
  390.         BlkBegLine++;
  391.         if ((int)(BlkBegLine - BlkBeg) == ClientWidth()-1)    {
  392.             while (*BlkBegLine != ' ' && BlkBegLine > BlkBeg)
  393.                 --BlkBegLine;
  394.             if (*BlkBegLine != ' ')    {
  395.                 BlkBegLine = strchr(BlkBegLine, ' ');
  396.                 if (BlkBegLine == NULL || BlkBegLine >= BlkEndLine)
  397.                     break;
  398.             }
  399.             int off = BlkBegLine - (const char *)*text;
  400.             (*text)[off] = '\n';
  401.             BlkBeg = BlkBegLine+1;
  402.         }
  403.     }
  404.     BuildTextPointers();
  405.     changed = True;
  406.     // --- put cursor back at beginning
  407.     column = BegCol;
  408.     if (FirstLine < wtop)
  409.         wtop = FirstLine;
  410.     row = FirstLine - wtop;
  411.     visible = True;
  412.     Paint();
  413.     ResetCursor();
  414. }
  415.  
  416. // --------- add a line of text to the editor textbox
  417. void Editor::AddText(const char *txt)
  418. {
  419.     // --- compute the buffer size based on tabs in the text
  420.     const char *tp = txt;
  421.     int x = 0;
  422.     int sz = 0;
  423.     while (*tp)    {
  424.         if (*tp == '\t')    {
  425.             // --- tab, adjust the buffer length
  426.             int sps = Tabs() - (x % Tabs());
  427.             sz += sps;
  428.             x += sps;
  429.         }
  430.         else    {
  431.             // --- not a tab, count the character
  432.             sz++;
  433.             x++;
  434.         }
  435.         if (*tp == '\n')
  436.             x = 0;    // newline, reset x
  437.         tp++;
  438.     }
  439.     // --- allocate a buffer
  440.     char *ep = new char[sz];
  441.     // --- detab the input file
  442.     tp = txt;
  443.     char *ttp = ep;
  444.     x = 0;
  445.     while (*tp)    {
  446.         // --- put the character (\t, too) into the buffer
  447.         *ttp++ = *tp;
  448.         x++;
  449.         // --- expand tab into one \t and pseudo-spaces (\t + 0x80)
  450.         if (*tp == '\t')
  451.             while ((x % Tabs()) != 0)
  452.                 *ttp++ = Ptab, x++;
  453.         else if (*tp == '\n')
  454.             x = 0;
  455.         tp++;
  456.     }
  457.     *ttp = '\0';
  458.     // ---- add the text to the editor window
  459.     EditBox::AddText(ep);
  460. }
  461.  
  462. // ------- retrieve editor text collapsing tabs
  463. const String Editor::GetText()
  464. {
  465.     char *tx = new char[text->Strlen()+1];
  466.     const char *tp = (const char *) *text;
  467.     char *nt = tx;
  468.     while (*tp)    {
  469.         if (*(const unsigned char *)tp != Ptab)
  470.             *tx++ = *tp;
  471.         tp++;
  472.     }
  473.     *tx = '\0';
  474.     String temp(nt);
  475.     return nt;
  476. }
  477.  
  478. void Editor::WriteString(String &ln, int x, int y, int fg, int bg)
  479. {
  480.     String nln(ln.Strlen());
  481.     int ch;
  482.     for (int i = 0; i < ln.Strlen(); i++)    {
  483.         ch = ln[i];
  484.         nln[i] = (ch & 0x7f) == '\t' ? ' ' : ch;
  485.     }
  486.     EditBox::WriteString(nln, x, y, fg, bg);
  487. }
  488.  
  489. void Editor::LeftButton(int mx, int my)
  490. {
  491.     if (ClientRect().Inside(mx, my))    {
  492.         column = mx-ClientLeft()+wleft;
  493.         row = my-ClientTop()+wtop;
  494.         if (row > wlines-1)
  495.             row = wlines+1;
  496.         ResetCursor();
  497.     }
  498.     else
  499.         TextBox::LeftButton(mx, my);
  500. }
  501.  
  502. // --------- clear the text from the editor window
  503. void Editor::ClearText()
  504. {
  505.     OpenWindow();
  506.     EditBox::ClearText();
  507. }
  508.  
  509.  
  510.